#include <iostream>
#include <string>
#include "httplib.h"
#include <stdio.h>
#include "log/logger.h"
#include "handler.h"
#include "face_api_helper.h"
#include "return_json_object.h"
#include "baidu_face_api.h"
#include "face_container.h"
#include "config.h"

using namespace std;
using namespace httplib;

std::string dump_headers(const Headers &headers) {
	std::string s;
	char buf[BUFSIZ];

	for (auto it = headers.begin(); it != headers.end(); ++it) {
		const auto &x = *it;
		snprintf(buf, sizeof(buf), "%s: %s\n", x.first.c_str(), x.second.c_str());
		s += buf;
	}

	return s;
}

std::string log(const Request &req, const Response &res) {
	std::string s;
	char buf[BUFSIZ];

	s += "================================\n";

	snprintf(buf, sizeof(buf), "%s %s %s", req.method.c_str(),
			req.version.c_str(), req.path.c_str());
	s += buf;

	std::string query;
	for (auto it = req.params.begin(); it != req.params.end(); ++it) {
		const auto &x = *it;
		snprintf(buf, sizeof(buf), "%c%s=%s",
				(it == req.params.begin()) ? '?' : '&', x.first.c_str(),
				x.second.c_str());
		query += buf;
	}
	snprintf(buf, sizeof(buf), "%s\n", query.c_str());
	s += buf;

	s += dump_headers(req.headers);

	s += "--------------------------------\n";

	snprintf(buf, sizeof(buf), "%d %s\n", res.status, res.version.c_str());
	s += buf;
	s += dump_headers(res.headers);
	s += "\n";

	if (!res.body.empty()) { s += res.body; }

	s += "\n";

	return s;
}



std::function<void(const Request&,Response&)> getHandler(const string& path,
		std::function<shared_ptr<BaseObjectIf>(const string&)> handler)
{

	return [path,handler](const Request& req, Response& res) {

		
		shared_ptr<BaseObjectIf> obj = handler(req.body);
		res.headers.emplace("Connection","close");
		string res_body = Serialize(obj);
		res.set_content(res_body, "application/json");
	};
}

void route(Server& svr)
{
	svr.Post("/face/attr", getHandler("/face/attr",handlerGetFaceAttr));
	svr.Post("/face/quality", getHandler("/face/quality",handlerGetFaceQuality));
	svr.Post("/face/feature", getHandler("/face/feature",handlerGetFaceFeature));
	svr.Post("/face/matchByImg", getHandler("/face/matchByImg",handlerMatchFaceByImg));
	svr.Post("/face/register", getHandler("/face/register",handlerRegisterFace));
	svr.Post("/face/search", getHandler("/face/search",handlerSearchFace));
	svr.Post("/face/multSearch", getHandler("/face/multSearch",handlerMultSearchFace));
	svr.Post("/face/remove", getHandler("/face/remove",handlerRemoveFace));
	svr.Post("/face/clear", getHandler("/face/clear",handlerClearFaces));

	svr.set_error_handler([](const Request & req /*req*/, Response &res) {
			shared_ptr<BaseObjectIf> obj = handlerNoHandler(req.body);
			res.headers.emplace("Connection","close");
			string res_body = Serialize(obj);
			res.set_content(res_body, "application/json");
			});

	svr.set_logger([](const Request &req, const Response &res) {
			fprintf(stderr,"%s",log(req, res).c_str());
			LOG(LOG_INFO, "%s", log(req,res).c_str());
			});
}

void parse_argv(int argc, char* argv[])
{
	auto ch = 0;
	while( (ch = getopt(argc, argv, "i:f:p:n:")) != -1)
	{

		fprintf(stderr,"optind: %d\n", optind);
		switch (ch) 
		{

			case 'i':
				fprintf(stderr,"have option: -i\n"); 
				fprintf(stderr,"the argument of -i is bind ip %s\n\n", optarg);
				Config::binding_ip = optarg;
				break;
			case 'f':
				fprintf(stderr,"have option: -f\n"); 
				fprintf(stderr,"the argument of -f is face db file %s\n\n", optarg);
				Config::face_db_file = optarg;
				break;

			case 'p':
				fprintf(stderr,"HAVE option: -p\n");
				fprintf(stderr,"the argument of -p is port %s\n\n",optarg);
				Config::binding_port = atoi(optarg);
				break;
			case 'n':
				fprintf(stderr,"HAVE option: -p\n");
				fprintf(stderr,"the argument of -n faces per async task %s\n\n",optarg);
				Config::faces_per_async_task = atoi(optarg);
				break;

			case '?':	
				fprintf(stderr,"Unknown option: %c\n",(char)optopt);
				break;
		}
	}
}


int main(int argc, char* argv[])
{
	string process(argv[0]);
	process = process.substr(2,-1); // remove "./"
	LOG_OPEN( process.c_str(), LOG_PID, LOG_LOCAL0);

	parse_argv(argc,argv);

	FaceApiHelper::getInstance()->sdk_init(false);

	shared_ptr<FaceSerializeIf> serial(new FileFaceSerialize(Config::face_db_file));
	FaceContainer::getInstance()->Init(serial);

	Server svr;
	if (!svr.is_valid()) {
	
		LOG(LOG_INFO,"server has an error...");
		return -1;
	}

	//注册路由
	route(svr);

	std::cout <<"string...." << std::endl;
	LOG( LOG_INFO, "Face Api Http Server(%s,%d) starting...", Config::binding_ip.c_str(), Config::binding_port);
	svr.listen(Config::binding_ip.c_str(), Config::binding_port);

	return 0;
}


